/*
Copyright (C) 1996-1997 GX Media, Inc.
Copyright (C) 2010 Ronie Salgado

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "stdafx.h"
#include "Qoole.h"
#include "QMainFrame.h"
#include "QooleDoc.h"
#include "QView.h"

#include "QVersion.h"
#include "QDraw.h"
#include "QView.h"
#include "LCommon.h"
#include "Quake.h"
#include "Quake2.h"
#include "Hexen2.h"
#include "HalfLife.h"
#include "Heretic2.h"
#include "Sin.h"
#include "XmlGame.h"

IMPLEMENT_APP(QooleApp);

QooleApp::QooleApp()
{
}

QooleApp::~QooleApp()
{
	Profile::iterator it = profile.begin();
	for(; it != profile.end(); it++)
		delete it->second;
}

// Generated automatically by wxrc
extern void InitXmlResource();

bool QooleApp::OnInit()
{
	// Set the app name.
	SetAppName(wxT(PACKAGE_NAME));

	// Set the numeric locale.
	setlocale(LC_NUMERIC, "C");

	// Add support fot png images.
	wxImage::AddHandler(new wxPNGHandler);

	// Load the resources.
	wxXmlResource::Get()->InitAllHandlers();
	InitXmlResource();

	// Create the document templates.
	new wxDocTemplate(&docManager, wxT("Qoole document"),
			wxT("*.xql"), wxT("")/*dir*/, wxT("xql"), wxT("QooleDoc"),
			wxT("QView"), CLASSINFO(QooleDoc), CLASSINFO(QView));
	new wxDocTemplate(&docManager, wxT("Classic Qoole 99 document"),
				wxT("*.qle"), wxT("")/*dir*/, wxT("qle"), wxT("QooleDoc"),
				wxT("QView"), CLASSINFO(QooleDoc), CLASSINFO(QView));
	new wxDocTemplate(&docManager, wxT("Map file"),
				wxT("*.map"), wxT("")/*dir*/, wxT("map"), wxT("QooleDoc"),
				wxT("QView"), CLASSINFO(QooleDoc), CLASSINFO(QView));
	new wxDocTemplate(&docManager, wxT("All files"),
					wxT("*"), wxT("")/*dir*/, wxT("*"), wxT("QooleDoc"),
					wxT("QView"), CLASSINFO(QooleDoc), CLASSINFO(QView));

	// Create the qoole config dir
	wxFileName configDirName;
	configDirName.AssignDir(wxStandardPaths::Get().GetUserConfigDir());
	configDirName.AppendDir(wxT(".config"));
	configDirName.AppendDir(wxT("qoole"));
	configDirName.Mkdir(0777, wxPATH_MKDIR_FULL);
	configDir = configDirName.GetPath();

	// Read the profile
	ReadProfile();

	// Qoole specific registry stuff.
	LConfig::Init(Q_CURRENT_VERSION, Q_REQUIRED_VERSION);

	// Initialize drawing subsystem
	QDraw::Init();
	QView::Init();

	// Create the main frame.
	QMainFrame *mainFrame = new QMainFrame();
	if(!mainFrame->Create(&docManager))
		return false;

	SetTopWindow(mainFrame);
	mainFrame->Show(true);

	// Initialize data file
	LFile::Init();

	wxString q99pak = LFile::GetInitDir() + wxT("Qoole99.pak");

	if (!LFile::Exist(q99pak)) {
		// Can't find the q99 pak file in the current working dir.
		// Try the same dir where the app is running from.
		q99pak = wxT("./Qoole99.pak");

		if (!LFile::Exist(q99pak)) // 2nd try.
			LFatal(_("Required file not found: %s"), q99pak.c_str());
	}

	LFile::UsePak(q99pak);

	// Register games
	new Quake;
	new Quake2;
	new Hexen2;
	new HalfLife;
	new Sin;
	new Heretic2;
	XmlGame::LoadGames();

	if(LFile::Exist(wxT("texlists/texture.db")))
	{
#ifdef _WIN32
		_unlink("texlists/texture.db");
#else
		unlink("texlists/texture.db");
#endif
	}
	return true;
}

int QooleApp::OnExit()
{
	// Clean up
	EntList::Exit();
	Game::Exit();
	QDraw::Exit();
	LFile::Exit();
	QView::Exit();

	LConfig::Exit();

	WriteProfile();
	return wxApp::OnExit();
}

QooleDocManager *QooleApp::GetDocManager()
{
	return &docManager;
}

int QooleApp::GetProfileInt(const wxString &section, const wxString &name, int def)
{
	// Get the section.
	ProfileSection *sec = GetProfileSection(section, false);
	if(!sec)
		return def;

	// Find the value.
	ProfileSection::iterator it = sec->find(name);
	if(it != sec->end())
		return atoi(it->second.utf8_str());

	return def;
}

void QooleApp::WriteProfileInt(const wxString &section, const wxString &name, int value)
{
	// Format the value.
	wxString fval = wxString::Format(wxT("%d"), value);

	// Get the section.
	ProfileSection *sec = GetProfileSection(section, true);

	// Find the value.
	ProfileSection::iterator it = sec->find(name);
	if(it != sec->end())
	{
		it->second = fval;
	}
	else
	{
		sec->insert(std::make_pair(name, fval));
	}
}

wxString QooleApp::GetProfileString(const wxString &section, const wxString &name)
{
	// Get the section.
	ProfileSection *sec = GetProfileSection(section, false);
	if(!sec)
		return wxEmptyString;

	// Find the value.
	ProfileSection::iterator it = sec->find(name);
	if(it != sec->end())
		return it->second;

	return wxEmptyString;
}

void QooleApp::WriteProfileString(const wxString &section, const wxString &name, const wxString &value)
{
	// Get the section.
	ProfileSection *sec = GetProfileSection(section, true);

	// Find the value.
	ProfileSection::iterator it = sec->find(name);
	if(it != sec->end())
	{
		it->second = value;
	}
	else
	{
		sec->insert(std::make_pair(name, value));
	}
}

QooleApp::ProfileSection *QooleApp::GetProfileSection(const wxString &section, bool create)
{
	// First find the section.
	Profile::iterator it = profile.find(section);
	if(it != profile.end())
		return it->second;

	if(!create)
		return NULL;

	// Then create it if it doesn't exist.
	ProfileSection *newSection = new ProfileSection();
	profile.insert(std::make_pair(section, newSection));
	return newSection;
}

void QooleApp::ReadProfile()
{
	wxFileName profileName;
	profileName.Assign(configDir, wxT("config.xml"));

	if(!profileName.IsFileReadable())
	{
		fprintf(stderr, "Unexistent configuration file.\n");
		return;
	}

	// Load the config document.
	wxXmlDocument doc;
	if(!doc.Load(profileName.GetFullPath()))
	{
		fprintf(stderr, "Failed to load the configuration.\n");
		return;
	}

	// Check the root element.
	if(doc.GetRoot()->GetName() != wxT("config"))
	{
		fprintf(stderr, "Invalid configuration file.\n");
		return;
	}

	// Read the sections.
	wxXmlNode *sectionNode = doc.GetRoot()->GetChildren();
	for(; sectionNode; sectionNode = sectionNode->GetNext())
	{
		// Ignore others nodes.
		if(sectionNode->GetName() != wxT("section"))
			continue;

		// Read the section name.
		wxString sectionName = sectionNode->GetAttribute(wxT("name"), wxEmptyString);

		// Ignore empty sections.
		if(sectionName.empty())
			continue;

		ProfileSection *section = GetProfileSection(sectionName, true);

		// Read the section properties.
		wxXmlNode *propNode = sectionNode->GetChildren();
		for(; propNode; propNode = propNode->GetNext())
		{
			// Ignore others nodes.
			if(propNode->GetName() != wxT("prop"))
				continue;

			// Read the name and the value.
			wxString name = propNode->GetAttribute(wxT("name"), wxEmptyString);
			wxString value = propNode->GetAttribute(wxT("value"), wxEmptyString);

			// Ignore properties with an empty name or value.
			section->insert(std::make_pair(name, value));
		}
	}

}

void QooleApp::WriteProfile()
{
	wxFileName profileName;
	profileName.Assign(configDir, wxT("config.xml"));

	// Create the document.
	wxXmlDocument doc;
	doc.SetVersion(wxT("1.0"));

	// Create the root node.
	wxXmlNode *rootNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("config"));
	doc.SetRoot(rootNode);

	// Save the sections.
	Profile::iterator it = profile.begin();
	for(; it != profile.end(); it++)
	{
		wxString sectionName = it->first;
		ProfileSection *section = it->second;

		// Create a node for the section
		wxXmlNode *sectionNode = new wxXmlNode(rootNode, wxXML_ELEMENT_NODE, wxT("section"));
		sectionNode->AddAttribute(wxT("name"), sectionName);

		// Save the section properties.
		ProfileSection::iterator it2 = section->begin();
		for(; it2 != section->end(); it2++)
		{
			wxString propName = it2->first;
			wxString propValue = it2->second;

			// Create a node for the property.
			wxXmlNode *propNode = new wxXmlNode(sectionNode, wxXML_ELEMENT_NODE, wxT("prop"));
			propNode->AddAttribute(wxT("name"), propName);
			propNode->AddAttribute(wxT("value"), propValue);
		}
	}

	// Save the document.
	if(!doc.Save(profileName.GetFullPath()))
	{
		fprintf(stderr, "Failed to write the configuration file.\n");
	}
}
